import axios, { type AxiosRequestConfig } from 'axios';
import { getBaseURL } from './utils';

// Create a new axios instance with default config
const http = axios.create({
  baseURL:getBaseURL(),
  timeout: 10000,
  withCredentials: true,
});

// Request interceptor to add auth token
http.interceptors.request.use((config) => {
  const token = localStorage.getItem('token');
  if (token) {
    config.headers.Authorization = `Bearer ${token}`;
  }
  return config;
});

// Response interceptor to handle errors and extract data
http.interceptors.response.use(
  (response) => response.data, // Automatically unwrap the response data
  async (error) => {
    if (error.response?.status === 401) {
      window.location.href = '/login';
    }
    
    // 统一处理错误消息，提取后端返回的详细错误信息
    let errorMessage = '请求失败';
    
    if (error.response?.data) {
      try {
        // 如果是 Blob 类型响应（如文件下载失败），需要先读取内容
        if (error.response.data instanceof Blob) {
          const text = await error.response.data.text();
          const data = JSON.parse(text);
          errorMessage = data.detail || errorMessage;
        } else if (typeof error.response.data === 'object' && error.response.data.detail) {
          // 普通 JSON 响应，直接获取 detail 字段
          errorMessage = error.response.data.detail;
        } else if (typeof error.response.data === 'string') {
          // 字符串类型响应
          errorMessage = error.response.data;
        }
      } catch (parseError) {
        // 解析失败时，根据状态码提供默认错误消息
        switch (error.response?.status) {
          case 404:
            errorMessage = '请求的资源不存在';
            break;
          case 500:
            errorMessage = '服务器内部错误';
            break;
          case 403:
            errorMessage = '没有权限访问该资源';
            break;
          default:
            errorMessage = `请求失败 (${error.response?.status || 'Unknown'})`;
        }
      }
    } else if (error.code === 'ECONNABORTED') {
      errorMessage = '请求超时，请稍后重试';
    } else if (error.code === 'ERR_NETWORK') {
      errorMessage = '网络连接失败，请检查网络';
    }
    
    // 将处理后的错误消息设置到 error.message 中，方便组件使用
    error.message = errorMessage;
    
    return Promise.reject(error);
  }
);

type RequestConfig = Omit<AxiosRequestConfig, 'url' | 'method' | 'data'>;

/**
 * A typed HTTP client that provides better TypeScript support and error handling
 */
export const typedHttp = {
  /**
   * Send a GET request
   * @param url The URL to send the request to
   * @param config Optional request config
   * @returns A promise that resolves to the response data
   */
  get: <T = any>(url: string, config?: RequestConfig): Promise<T> => 
    http.get<T, T>(url, config),

  /**
   * Send a POST request
   * @param url The URL to send the request to
   * @param data The data to send in the request body
   * @param config Optional request config
   * @returns A promise that resolves to the response data
   */
  post: <T = any, D = any>(url: string, data?: D, config?: RequestConfig): Promise<T> => 
    http.post<T, T, D>(url, data, config),

  /**
   * Send a PUT request
   * @param url The URL to send the request to
   * @param data The data to send in the request body
   * @param config Optional request config
   * @returns A promise that resolves to the response data
   */
  put: <T = any, D = any>(url: string, data?: D, config?: RequestConfig): Promise<T> => 
    http.put<T, T, D>(url, data, config),

  /**
   * Send a DELETE request
   * @param url The URL to send the request to
   * @param config Optional request config
   * @returns A promise that resolves to the response data
   */
  delete: <T = void>(url: string, config?: RequestConfig): Promise<T> => 
    http.delete<T, T>(url, config),

  /**
   * Send a PATCH request
   * @param url The URL to send the request to
   * @param data The data to send in the request body
   * @param config Optional request config
   * @returns A promise that resolves to the response data
   */
  patch: <T = any, D = any>(url: string, data?: D, config?: RequestConfig): Promise<T> => 
    http.patch<T, T, D>(url, data, config),
};

export default typedHttp;
